package edu.xhu.minio.clients;

import com.jcraft.jsch.*;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 自定义SSH客户端
 */
@Slf4j
@Data
@Accessors(chain = true)
public class BiliSSHCilent {
    /**
     * ssh会话连接
     */
    private Session session;

    /**
     * 客户端ip地址
     */
    private String host;

    /**
     * 用户名
     */
    private String user;

    /**
     * 密码
     */
    private String passwd;


    /**
     * 连接到指定的host
     */
    public boolean connect() {
        JSch jSch = new JSch();
        try {
            session = jSch.getSession(user, host, 22);
            session.setPassword(passwd);
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();
        } catch (JSchException e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }


    /**
     * 检查客户端是否已连接
     *
     * @return
     */
    public boolean isConnected() {
        return session != null && session.isConnected();
    }


    /**
     * 断开SSH连接
     */
    public void disconnect() {
        if (session != null && session.isConnected()) {
            session.disconnect();
            System.out.println("Disconnected from " + host);
        }
    }

    /**
     * 输出服务器的剩余磁盘空间，以 GB 为单位
     */
    public Double getAvailableDiskSpaceInGB() {
        if (!this.isConnected()) {
            return (double) -1;
        }
        return this.getServerResourceInfo().get("IO").get(2);
    }

    /**
     * 返回当前服务器CPU，内存，磁盘信息
     *
     * @return Map = { CPU:[],MEM:[],IO:[] }, CPU,MEM,IO,可能为null,取的时候记得抛异常
     */
    public Map<String, List<Double>> getServerResourceInfo() {
        if (!this.isConnected()) {
            return null;
        }
        return this.getLinuxStateByShell(disposeResultMessage(runDistanceShell()));
    }

    /**
     * 内置好的命令
     */
    private final String CPU_MEM_SHELL = "top -b -n 1";

    private final String FILES_SHELL = "df -hl";

    private final String[] COMMANDS = {CPU_MEM_SHELL, FILES_SHELL};

    private final String LINE_SEPARATOR = System.getProperty("line.separator");

    private final String MSG = "/dev/vda1";

    /**
     * 远程链接Linux服务器，执行内置的相关命令
     */
    private Map<String, String> runDistanceShell() {
        if (!this.isConnected()) {
            return null;
        }
        HashMap<String, String> map = new HashMap<>();
        StringBuilder stringBuilder;
        BufferedReader reader = null;
        Channel channel = null;
        try {
            for (String command : COMMANDS) {
                stringBuilder = new StringBuilder();
                channel = session.openChannel("exec");
                ((ChannelExec) channel).setCommand(command);
                channel.setInputStream(null);
                ((ChannelExec) channel).setErrStream(System.err);
                channel.connect();
                InputStream inputStream = channel.getInputStream();
                reader = new BufferedReader(new InputStreamReader(inputStream));
                String buf;
                while ((buf = reader.readLine()) != null) {
                    //舍弃PID，进程信息
                    if (buf.contains("PID")) {
                        break;
                    }
                    stringBuilder.append(buf.trim()).append(LINE_SEPARATOR);
                }
                map.put(command, stringBuilder.toString());
            }
        } catch (IOException | JSchException e) {
            log.error(e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
            if (channel != null) {
                channel.disconnect();
            }
        }

        return map;
    }

    /**
     * 封装一个返回类，返回服务器CPU，内存，磁盘信息
     * Map = { CPU:[],MEM:[],IO:[] }
     * CPU,MEM,IO,可能为null,取的时候记得抛异常
     */
    private Map<String, List<Double>> getLinuxStateByShell(String result) {
        String[] split = result.split(LINE_SEPARATOR);
        Map<String, List<Double>> map = new HashMap<>();
        List<Double> cpu = new ArrayList<>();
        List<Double> mem = parseMem(split[1]);
        List<Double> io = parseIO(split[2]);
        cpu.add(Double.parseDouble(split[0].split(":")[1].trim()));
        map.put("CPU", cpu);
        map.put("MEM", mem);
        map.put("IO", io);
        return map;
    }

    /**
     * 处理shell返回信息
     */
    private String disposeResultMessage(Map<String, String> result) {
        StringBuilder buffer = new StringBuilder();
        for (String command : COMMANDS) {
            String commandResult = result.get(command);
            if (commandResult == null) {
                continue;
            }
            if (command.equalsIgnoreCase(CPU_MEM_SHELL)) {
                String[] split = commandResult.split(LINE_SEPARATOR);
                for (String line : split) {
                    line = line.toUpperCase();
                    //处理CPU
                    if (line.startsWith("%CPU(S):")) {
                        String cpuStr = "CPU 用户使用占有率:";
                        try {
                            cpuStr += line.split(":")[1].split(",")[0].replace("US", "");
                        } catch (Exception e) {
                            log.error(e.getMessage());
                            cpuStr += "计算过程出错！";
                        }
                        buffer.append(cpuStr).append(LINE_SEPARATOR);
                    }
                    //处理内存
                    else if (line.startsWith("KIB MEM")) {
                        String memStr = "内存使用情况:";
                        try {
                            memStr += line.split(":")[1].replace("TOTAL", "总计")
                                    .replace("USED", "已使用")
                                    .replace("FREE", "空闲")
                                    .replace("BUFFERS", "缓存");
                        } catch (Exception e) {
                            log.error(e.getMessage());
                            memStr += "计算过程出错";
                            buffer.append(memStr).append(LINE_SEPARATOR);
                        }
                        buffer.append(memStr).append(LINE_SEPARATOR);
                    }
                }
            } else if (command.equalsIgnoreCase(FILES_SHELL)) {
                //处理磁盘系统
                buffer.append("系统磁盘状态:");
                try {
                    buffer.append(disposeFilesSystem(commandResult)).append(LINE_SEPARATOR);
                } catch (Exception e) {
                    log.error(e.getMessage());
                    buffer.append("计算过程出错").append(LINE_SEPARATOR);
                }
            }
        }
        return buffer.toString();
    }

    /**
     * 处理磁盘状态
     */
    private List<String> disposeFilesSystem(String commandResult) {
        String[] split = commandResult.split(LINE_SEPARATOR);
        String text = null;
        for (String s : split) {
            if (s.contains(MSG)) {
                text = s;
                break;
            }
        }
        if (text == null) {
            return null;
        }
        String[] s = text.trim().split(" ");
        //遍历s
        List<String> arr = new ArrayList<>();
        for (int i = 1; i < s.length - 1; i++) {
            if (!s[i].isEmpty()) {
                arr.add(s[i]);
            }
        }
        if (arr.size() >= 4) {
            return arr;
        }
        return null;
    }

    private static List<Double> parseIO(String s) {
        // 提取括号内的内容
        Pattern bracketPattern = Pattern.compile("\\[(.*)\\]");
        Matcher bracketMatcher = bracketPattern.matcher(s);

        if (bracketMatcher.find()) {
            String content = bracketMatcher.group(1);

            // 使用逗号分隔内容
            String[] parts = content.split(",\\s*");
            List<Double> numbers = new ArrayList<>();

            // 使用正则表达式提取数字部分
            Pattern numberPattern = Pattern.compile("\\d+(\\.\\d+)?");
            for (String part : parts) {
                Matcher numberMatcher = numberPattern.matcher(part);
                if (numberMatcher.find()) {
                    numbers.add(Double.parseDouble(numberMatcher.group()));
                }
            }
            return numbers;
        }
        return null;
    }

    private static List<Double> parseMem(String s) {
        String[] split = s.split(":");
        if (split.length > 1) {
            String part = split[1];
            Pattern pattern = Pattern.compile("\\d+");
            Matcher matcher = pattern.matcher(part);
            List<Double> numbers = new ArrayList<>();
            while (matcher.find()) {
                numbers.add(Double.parseDouble(matcher.group()));
            }
            return numbers;
        }
        return null;
    }
}
